package com.assignwork.modules.plan.service.impl;

import com.assignwork.dto.*;
import com.assignwork.entity.*;
import com.assignwork.mapper.GroupDispatchMapper;
import com.assignwork.mapper.PlanMapper;
import com.assignwork.modules.plan.service.IPlanService;
import com.assignwork.service.*;
import com.assignwork.vo.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import lombok.AllArgsConstructor;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.DictBizCache;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class PlanServiceImpl implements IPlanService {

    PlanMapper planMapper;
    IDailyPlanService dailyPlanService;
    IAssemblyLineService assemblyLineService;
    IJobConfigService configService;
    IStartedCabinService startedCabinService;
    IDynamicFormService formService;
    IDynamicFormDataService formDataService;
    GroupDispatchMapper groupDispatchMapper;
    IShipDynamicService shipDynamicService;
    IVoyageBillCabinService billCabinService;

    @Override
    public WeatherTideVO weatherTide(BladeUser bladeUser, String planDate) {
        WeatherTideVO weather = planMapper.weather(planDate);
        if (weather == null) {
            weather = new WeatherTideVO();
        }
        List<TideVO> tide = planMapper.tide(planDate);
        weather.setTide(tide);
        return weather;
    }

    @Override
    public boolean copyFromYesterday(BladeUser bladeUser, DailyPlanDTO input) {
        LocalDate planDate = input.getPlanDate();
        String planner = input.getPlanner();
        LocalDate yesterday = input.getPlanDate().minusDays(1);

        List<DynamicForm> leadership = formService.list(
                new QueryWrapper<DynamicForm>()
                        .lambda()
                        .eq(DynamicForm::getFormDate, yesterday)
                        .in(DynamicForm::getFormType, new String[]{"MATTERS"})
                        .orderByDesc(DynamicForm::getUpdateTime)
        );

        for (DynamicForm dynamicForm : leadership) {
            Long formId = dynamicForm.getId();

            List<DynamicFormData> formDatas = formDataService.list(
                    new QueryWrapper<DynamicFormData>()
                            .lambda()
                            .eq(DynamicFormData::getFormId, formId)
                            .eq(DynamicFormData::getStatus, 1)
            );

            List<DynamicFormDataDTO> newFormData = formDatas.stream().map(i -> {
                DynamicFormDataDTO copy = Func.copy(i, DynamicFormDataDTO.class);
                copy.setId(null);
                return copy;
            }).collect(Collectors.toList());

            DynamicFormDTO newForm = Func.copy(dynamicForm, DynamicFormDTO.class);
            newForm.setId(null);
            newForm.setFormDate(planDate);
            newForm.setData(newFormData);

            formService.saveOrUpdateLeadershipComments(bladeUser, newForm);
        }

        List<DailyPlan> plans = dailyPlanService.list(
                new QueryWrapper<DailyPlan>()
                        .lambda()
                        .eq(DailyPlan::getPlanDate, yesterday)
        );

        for (DailyPlan plan : plans) {
            Long planId = plan.getId();

            List<AssemblyLine> lines = assemblyLineService.list(
                    new QueryWrapper<AssemblyLine>()
                            .lambda()
                            .eq(AssemblyLine::getPlanId, planId)
            );

            plan.setId(null);
            plan.setPlanDate(planDate);
            plan.setPlanner(planner);
            plan.setStatus(1);
            dailyPlanService.saveOrUpdate(plan);
            Long newPlanId = plan.getId();

            for (AssemblyLine line : lines) {
                Long lineId = line.getId();
                List<JobConfig> jobs = configService.list(
                        new QueryWrapper<JobConfig>()
                                .lambda()
                                .eq(JobConfig::getLineId, lineId)
                );

                List<StartedCabin> cabins = startedCabinService.list(
                        new QueryWrapper<StartedCabin>()
                                .lambda()
                                .eq(StartedCabin::getLineId, lineId)
                );

                line.setId(null);
                line.setPlanId(newPlanId);
                line.setLineNo(assemblyLineService.generateLineNo());
                line.setPlanDate(line.getPlanDate().plusDays(1));
                assemblyLineService.saveOrUpdate(line);
                Long newLineId = line.getId();

                List<JobConfig> newJobs = jobs.stream().map(i -> {
                    i.setPlanId(newPlanId);
                    i.setLineId(newLineId);
                    i.setId(null);
                    return i;
                }).collect(Collectors.toList());

                configService.saveOrUpdateBatch(newJobs);

                Map<String, List<StartedCabin>> collect = cabins.stream().collect(Collectors.groupingBy(StartedCabin::getGroupFg));

                for (Map.Entry<String, List<StartedCabin>> entry : collect.entrySet()) {
                    String key = entry.getKey();
                    List<StartedCabin> value = entry.getValue();
                    String fg = Func.randomUUID();

                    char index = key.charAt(0);
                    List<StartedCabin> newCabins = value.stream().map(i -> {
                        i.setGroupFg(index + fg);
                        i.setPlanId(newPlanId);
                        i.setLineId(newLineId);
                        i.setId(null);
                        return i;
                    }).collect(Collectors.toList());

                    startedCabinService.saveOrUpdateBatch(newCabins);
                }
            }
        }

        return false;
    }

    @Override
    public List<GroupDayStatPlanVO> listDayStatPlan(Query query, String keyword) {
        List<OrderItem> order = Condition.getOrder(query);
        order.add(new OrderItem(){{
            setAsc(true);
            setColumn("stat_time");
        }});
        List<GroupDayStatPlanVO> dayStatPlanVOS = groupDispatchMapper.listDayStatPlanVO(order, keyword);
        for (GroupDayStatPlanVO dayStatPlanVO : dayStatPlanVOS) {
            if (Func.isBlank(dayStatPlanVO.getBerthName())) {
                dayStatPlanVO.setBerthName(DictBizCache.getValue("ship_dynamics", dayStatPlanVO.getBerthCode()));
            }

            if (Func.isBlank(dayStatPlanVO.getPlanBerthName())) {
                dayStatPlanVO.setPlanBerthName(DictBizCache.getValue("ship_dynamics", dayStatPlanVO.getPlanBerthCode()));
            }
        }
        return dayStatPlanVOS;
    }

    @Override
    public boolean importData(BladeUser bladeUser, ImportDataDTO dto) {
        List<GroupDayStatPlanVO> vos = this.listDayStatPlan(null, dto.getKeyword());
        List<ShipDynamic> res = new ArrayList<>();
        for (GroupDayStatPlanVO vo : vos) {
            res.add(new ShipDynamic(){{
                setPlanDate(dto.getPlanDate());
                setPlanner(dto.getPlanner());
                setSourceData(Func.toJson(vo));
                StringBuffer sb = new StringBuffer("");
                if (Func.isNoneBlank(vo.getBegCable())) {
                    sb.append(vo.getBegCable());
                    sb.append(" / ");
                }
                if (Func.isNoneBlank(vo.getEndCable())) {
                    sb.append(vo.getEndCable());
                }
                setPlanBerth(sb.toString());
            }});
        }

        return shipDynamicService.saveOrUpdateBatch(res);
    }

    @Override
    public String getPlanTotalByVoyage(BladeUser bladeUser, DailyPlanDTO dto) {
        return planMapper.getPlanTotalByVoyage(dto);
    }

    @Override
    public Object getStartedCabinTon(BladeUser bladeUser, DailyPlanDTO dto) {
        if (DailyPlanDTO.PACKAGE_BULK_BULK.equals(dto.getPackageBulkKey())) {
            return this.planMapper.cabinTonByShip(dto.getShipName(), dto.getVoyage());
        } else if (DailyPlanDTO.PACKAGE_BULK_GROCERY.equals(dto.getPackageBulkKey())) {
            return this.billCabinService.cabinTonByShip(dto.getSourceId(), dto.getVoyage());
        }
        return null;
    }

    @Override
    public RealLineWorkInfoVO detailRealLineInfo(LocalDate planDate) {
        List<RealLineWorkInfoVO> ls = planMapper.detailRealLineInfo(planDate);
        return RealLineWorkInfoVO.arr2VO(ls);
    }
}
